﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


/////////Grammatik:

//START -> DEFLIST
//DEFLIST -> DEFINITION DEFLIST | €
//DEFINITION ->  "meta" "::=" EXPRESSION ";"
//EXPRESSION -> EXPRESSION "|" TERM
//EXPRESSION -> TERM

//TERM -> TERM FACTOR
//TERM -> FACTOR

//FACTOR -> "[" EXPRESSION "]"
//FACTOR -> "{" EXPRESSION "}"
//FACTOR -> "(" EXPRESSION ")"
//FACTOR -> "<" EXPRESSION ">"

//FACTOR -> "meta"
//FACTOR -> "'token'"

//() struktur
//{} 0 or N
//[] 0 or 1
//| alternative 

namespace Compiler
{
    public static class EBNF_Parser
    {
        public static Parser Build()
        {
            Terminal token = new Terminal(0, "TOKEN");
            Terminal meta = new Terminal(1, "META");
            Terminal assign = new Terminal(2, "=");
            Terminal semicolon = new Terminal(3, ";");
            Terminal alternate = new Terminal(4, "|");
            Terminal lb = new Terminal(5, "(");
            Terminal rb = new Terminal(6, ")");
            Terminal lcb = new Terminal(7, "{");
            Terminal rcb = new Terminal(8, "}");
            Terminal lsb = new Terminal(9, "[");
            Terminal rsb = new Terminal(10, "]");
            Terminal lab = new Terminal(11, "<");
            Terminal rab = new Terminal(12, ">");
            Terminal eps = new Terminal(13, "eps");

            Terminal use = new Terminal(20, "use");
            Terminal lexer = new Terminal(21, "lexer");
            Terminal parser = new Terminal(22, "parser");

            Terminal colon = new Terminal(30, "colon");
            Terminal integer = new Terminal(32, "integer");

           // Terminal newLine = new Terminal(40, "newline");
         //   Terminal anyCharExpectNewLine = new Terminal(40, ".");

            //RegEx reservierte Zeichen
            //\ * + ? | { [ () ^ $ . #     

            Token _token = new Token(@"""(\\.|[^\\""\n])*""", "TOKEN", Int32.MaxValue, token);
            Token _meta = new Token(@"@?[a-zA-Z_][a-zA-Z0-9_]*", "META", Int32.MaxValue, meta);
            Token _assign = new Token("=", "=", 1, assign);
            Token _semicolon = new Token(";", ";", 1, semicolon);
            Token _alternate = new Token(@"\|", "|", 1, alternate);
            Token _lb = new Token(@"\(", "(", 1, lb);
            Token _rb = new Token(@"\)", ")", 1, rb);
            Token _lcb = new Token(@"\{", "{", 1, lcb);
            Token _rcb = new Token(@"\}", "}", 1, rcb);
            Token _lsb = new Token(@"\[", "[", 1, lsb);
            Token _rsb = new Token(@"\]", "]", 1, rsb);
            Token _lab = new Token("<", "<", 1, lab);
            Token _rab = new Token(">", ">", 1, rab);
            Token _eps = new Token("EPS", "EPS", 3, eps);

            Token _use = new Token(@"\#(?i)Use", "Use", 4, use);
            Token _lexer = new Token(@"\#(?i)Lexer", "Lexer", 6, lexer);
            Token _parser = new Token(@"\#(?i)Parser", "Parser", 7, parser);

            Token _colon = new Token(":", ":", 1, colon);
            Token _integer = new Token("0|[1-9][0-9]*", "INT", 5, integer);

          //  Token _newLine = new Token("\n", "NEWLINE", 1, newLine);
          //  Token _anyCharExpectNewLine = new Token(".", "any", Int32.MaxValue, anyCharExpectNewLine);

            Nonterminal START = new Nonterminal(0, "START");
            Nonterminal PDEFLIST = new Nonterminal(1, "PDEFLIST");
            Nonterminal PDEFINITION = new Nonterminal(2, "PDEFINITION");
            Nonterminal EXPRESSION = new Nonterminal(3, "EXPRESSION");
            Nonterminal TERM = new Nonterminal(4, "TERM");
            Nonterminal FACTOR = new Nonterminal(5, "FACTOR");

            Nonterminal PROGRAM = new Nonterminal(10, "PROGRAM");
            Nonterminal USE = new Nonterminal(12, "USE");
            Nonterminal LEXER = new Nonterminal(14, "LEXER");
            Nonterminal PARSER = new Nonterminal(16, "PARSER");

            Nonterminal LDEFLIST = new Nonterminal(20, "LDEFLIST");
            Nonterminal LDEFINITION = new Nonterminal(21, "LDEFINITION");

            var productionList = new []
            { 
                    new Production(0, START, PROGRAM),

                    new Production(10, PROGRAM, use, lcb, USE, rcb, lexer, lcb, LEXER, rcb, parser, lcb, PARSER, rcb),

                    new Production(50, USE, Symbol.Epsilon),
                    
                    //new Production(70, LEXER, Symbol.Epsilon),
                    
                    new Production(80, LEXER, LDEFLIST),
                    new Production(90, LDEFLIST, LDEFINITION, LDEFLIST),
                    new Production(91, LDEFLIST, Symbol.Epsilon),
                    new Production(92, LDEFINITION, integer, colon, token, assign),

                    new Production(100, PARSER, PDEFLIST),
                    new Production(101, PDEFLIST, PDEFINITION, PDEFLIST), //A::=B ; C::=D;
                    new Production(102, PDEFLIST, Symbol.Epsilon),
                    new Production(103, PDEFINITION, integer, colon, meta, assign, EXPRESSION, semicolon), // A = ... ;
                    
                    new Production(104, EXPRESSION, EXPRESSION, alternate, TERM),  //  A | B   alternative

                    new Production(105, EXPRESSION, TERM),
                    new Production(106, TERM, TERM, FACTOR), // A B C    konkatenation von ausdrücken
                    new Production(107, TERM, FACTOR), 

                    new Production(108, FACTOR, lsb, EXPRESSION, rsb), // [A]
                    new Production(109, FACTOR, lcb, EXPRESSION, rcb), // {A}
                    new Production(110, FACTOR, lb, EXPRESSION, rb),  // (A)
                    new Production(111, FACTOR, lab, EXPRESSION, rab), // <A>

                    new Production(112, FACTOR, meta),
                    new Production(113, FACTOR, token),
                    new Production(114, FACTOR, eps)
            };

            Lexer lexer_ = new Lexer(new List<Token> {
                _use, _lexer, _parser, _eps, _token, _meta, 
                _assign, _semicolon, _alternate, 
                _lb, _rb, _lcb, _rcb, _lsb, _rsb, _lab, _rab,
                _colon, _integer });

            //var en = lexer_.GetEnumerator();
            //lexer_.SetSource(File.ReadAllText(@"C:\World\Projects\Compiler\Compiler\EbnfExample.txt"));
            //while (en.MoveNext())
            //{
            //    Console.WriteLine(en.Current.Token.ToString());
            //}
            return new Parser(
                Builder.Build(new Grammar(START, productionList), Builder.BuildMethod.LR1, null),
                lexer_,
                 new EBNF_NodeFactory()
                );
        }
    }
}
